#include "StdAfx.h"
#include "VFlowLayout.h"

// VFlowLayoutLineEdit ////////////////////////////////////////////////////////

//
VFlowLayoutLineEdit::VFlowLayoutLineEdit(QWidget *parent)
	:QLineEdit(parent)
{
	setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
	setTextMargins(0,0,0,0);
	setContentsMargins(0,0,0,0);
	//setFrame(false);

	connect(
		this,SIGNAL( textChanged(const QString &) ),
		this,SLOT( slotTextChanged() )
		);

	//slotTextChanged();
}

//
void VFlowLayoutLineEdit::slotTextChanged()
{
	QSize size = sizeHint();
		size.setWidth(calcWidth());

	setMaximumSize(size);
	setMinimumSize(size);
}

//
int VFlowLayoutLineEdit::calcWidth() const
{
	QFontMetrics fm = fontMetrics();
	return fm.width(displayText().length() > 0 ? displayText() : "X") + 10;
}

// VFlowLayoutTextEdit ////////////////////////////////////////////////////////

//
VFlowLayoutTextEdit::VFlowLayoutTextEdit(QWidget *parent) 
	:QTextEdit(parent)
	,m_eWidth(EWidth_expanding)
	,m_flowLayout(NULL)
	,m_inFlowLayout(true)
{
	setAcceptRichText(true);

	
	/*
	QSizePolicy sp = sizePolicy();
		sp.setVerticalPolicy(QSizePolicy::Fixed);
		sp.setHorizontalPolicy(QSizePolicy::Fixed);
	setSizePolicy(sp);
	*/

	setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
	setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);

	setContentsMargins(0,0,0,0);
	document()->setDocumentMargin(0);
	//document()->setUseDesignMetrics(true);

	connect(
		document(),SIGNAL( contentsChanged() ),
		this,SLOT( slotContentsChanged() )
	);

	//setInFlowLayout(true);

/*
	QFontMetrics fm(document()->defaultFont());
	QSize size(fm.width('W') + dW(),fm.height() + dH());

	setMaximumSize(size);
	setMinimumSize(size);
*/	
}

//
void VFlowLayoutTextEdit::setInFlowLayout(bool v)
{
	m_inFlowLayout = v;

	QSizePolicy sp = sizePolicy();
		sp.setVerticalPolicy(QSizePolicy::Fixed);
		sp.setHorizontalPolicy(v ? QSizePolicy::Fixed : QSizePolicy::Preferred);
	setSizePolicy(sp);

	if (m_inFlowLayout) {
		QFontMetrics fm(document()->defaultFont());
		QSize size(fm.width('W') + dW(),fm.height() + dH());

		setMaximumSize(size);
		setMinimumSize(size);
	}
	else {
		QFontMetrics fm(document()->defaultFont());
		int height = fm.height() + dH();

		setMinimumHeight(height);
		setMaximumHeight(height);
	}

}

//
int VFlowLayoutTextEdit::pageWidth() const 
{ 
	if (m_flowLayout) {
		return m_flowLayout->pageWidth();
	}
	return 0;
}

//
QSize VFlowLayoutTextEdit::calcFixedSize() const
{
	int textWidth = pageWidth() > 0 ? pageWidth() - dW() : 0;

	if (document()->textWidth() != textWidth) {
		document()->setTextWidth(textWidth);
	}

	int width = document()->size().width();
	int height = document()->size().height();

	if (height == 0) {
		QFontMetrics fm(document()->defaultFont());

		width = fm.width('X');
		height = fm.height();
	}

	height += dH();
	width += dW();

	return QSize(width,height);
}

//
QSize VFlowLayoutTextEdit::calcMaximumSize() const
{
	int width = 0;
	int height = 0;

	for (QTextBlock block = document()->begin(); block != document()->end(); block = block.next()) {
		int hBlock = 0;
		int wBlock = 0;

		QTextBlock::iterator it = block.begin();

		if (it.atEnd()) {
			const QTextCharFormat cf = block.charFormat();
			QFontMetrics fm(cf.font());

			wBlock += fm.width('X');
			hBlock = qMax(hBlock,fm.height());
		}
		else while (!it.atEnd()) {
			const QTextFragment currentFragment = it.fragment();

			if (currentFragment.isValid()) {
				const QTextCharFormat cf = currentFragment.charFormat();

				if (cf.isValid()) {
					QFontMetrics fm(cf.font());

					wBlock += fm.width(currentFragment.text());
					hBlock = qMax(hBlock,fm.height());
				}
			}

			++it;				
		}

		width = qMax(width,wBlock);
		height += hBlock;
	}

	if (height == 0) {
		QFontMetrics fm(document()->defaultFont());

		width = fm.width('X');
		height = fm.height();
	}
	
	height += dH();
	width += dW();

	return QSize(width,height);
}

//
QSize	VFlowLayoutTextEdit::calcSizeHint() const
{
	if (!m_inFlowLayout) {
		return QTextEdit::sizeHint();
	}

	if (m_eWidth == EWidth_page) {
		return calcFixedSize();
	}
	return calcMaximumSize();
}

//
int VFlowLayoutTextEdit::calcFontAscent() const
{
	if (document()->blockCount() > 1) {
		return 0;
	}

	int ascent = 0;
	QTextBlock block = document()->begin();
	QTextBlock::iterator it = block.begin();

	if (it.atEnd()) {
		const QTextCharFormat cf = block.charFormat();
		QFontMetrics fm(cf.font());

		ascent = fm.ascent();
	}
	else while (!it.atEnd()) {
		const QTextFragment currentFragment = it.fragment();

		if (currentFragment.isValid()) {
			const QTextCharFormat cf = currentFragment.charFormat();

			if (cf.isValid()) {
				QFontMetrics fm(cf.font());

				ascent = qMax(ascent,fm.ascent());
			}
		}

		++it;				
	}

	return ascent;
}

//
QSize	VFlowLayoutTextEdit::sizeHint() const
{
	return calcSizeHint();
}

//
void VFlowLayoutTextEdit::slotContentsChanged()
{
	QString s = toHtml();
	
	if (m_inFlowLayout) {
		QSize size = calcMaximumSize();
		//setEWidth(EWidth_expanding);

		if (size.width() > pageWidth()) {
			size = calcFixedSize();
			//setEWidth(EWidth_page);
		}

		setMaximumSize(size);
		setMinimumSize(size);
	}
	else {
		int width = this->width() - dW();
		if (document()->textWidth() != width) {
			document()->setTextWidth(width);
		}

		int height = document()->size().height() + dH();

		setMinimumHeight(height);
		setMaximumHeight(height);
		
		//setMaximumWidth(QTextEdit::maximumWidth());
		//setMinimumWidth(QTextEdit::minimumWidth());
	}
}

// class VFlowLayoutSplitter //////////////////////////////////////////////////

//
VFlowLayoutSplitter::VFlowLayoutSplitter(VFlowLayout *flowLayout)
	:m_flowLayout(flowLayout)
{
}

//
void VFlowLayoutSplitter::splitForWidth(int width,const QList<QLayoutItem*> &itemList)
{
//qDebug() << "VFlowLayoutSplitter::splitForWidth() " << width;

	int oldRowsCount = m_rows.count();
	int currWidth = 0;
	int currRow = 0;

	m_rows.clear();
	m_rows << VCols();

	for (int i = 0; i < itemList.count(); ++i) {
		QLayoutItem *item = itemList[i];

		VFlowLayoutTextEdit *textEdit = qobject_cast<VFlowLayoutTextEdit*>(item->widget());
		if (textEdit) {
			VFlowLayoutTextEdit::EWidth oldEWidth = textEdit->eWidth();
			
//int ww = textEdit->calcMaximumSize().width();
//qDebug() << ww << ",  " << oldEWidth;
			
			if (textEdit->calcMaximumSize().width() >= width) {
				textEdit->setEWidth(VFlowLayoutTextEdit::EWidth_page);
				//textEdit->document()->setTextWidth(width);
			}
			else {
				textEdit->setEWidth(VFlowLayoutTextEdit::EWidth_expanding);
				//textEdit->document()->setTextWidth(0);
			}
			
			if (oldEWidth != textEdit->eWidth()) {
				m_flowLayout->invalidate();
			}
		}

		currWidth += sizeHint(item).width();
		m_rows[currRow] << item;

		if (i+1 < itemList.count()) {
			int nextWidth = sizeHint(itemList[i+1]).width();

			if (currWidth + nextWidth > width) {
				currWidth = 0;
				currRow++;
				m_rows << VCols();
			}
		}
	}

	if (oldRowsCount != m_rows.count()) {
		m_flowLayout->invalidate();
/*
		//QObject *pp = m_flowLayout->parent();
		QLayout *parent = qobject_cast<QLayout*>(m_flowLayout->parent());
		if (parent) {
			parent->invalidate();
		}
*/		
	}


	//qDebug() << "width:" << width << " rows:" << m_rows.count() << " ww:" << ww;
}

//
QSize VFlowLayoutSplitter::currentSize(const QList<QLayoutItem*> &itemList)
{
	//if (m_rows.count() == 0) {
	//	m_rows << itemList;
	//}

	QSize size(0,0);
	int hRows = 0;

	foreach (const VCols cols,m_rows) {
		int hCols = 0;
		int wCols = 0;

		foreach (QLayoutItem *item,cols) {
			hCols = qMax(hCols,sizeHint(item).height());
			//hCols = qMax(hCols,item->minimumSize().height());
			wCols += sizeHint(item).width();
		}

		hRows += hCols;
		size.setWidth(qMax(size.width(),wCols));
	}

	size.setHeight(hRows);
	return size;
}

//
QSize VFlowLayoutSplitter::minimumSize(const QList<QLayoutItem*> &itemList)
{
	int width = 0;

	foreach (QLayoutItem *item,itemList) {
		//s = s.expandedTo(item->minimumSize());
		width = qMax(width,minimumSize(item).width());
	}

	QSize size(width,currentSize(itemList).height());
		//size += QSize(2*margin(), 2*margin());

	return size;
}

//
QSize VFlowLayoutSplitter::fixedSize(const QList<QLayoutItem*> &itemList)
{
	int width = 0;

	foreach (QLayoutItem *item,itemList) {
		width += minimumSize(item).width();
	}

	QSize size(width,currentSize(itemList).height());
		//size += QSize(2*margin(), 2*margin());

	return size;
}

//
void VFlowLayoutSplitter::calcMaxAscent(const VCols &cols,int &maxAscent,int &wCols)
{
	foreach (QLayoutItem *item,cols) {
		wCols += sizeHint(item).width();

		if (item->widget()) {
			QLineEdit *lineEdit = NULL;
			VFlowLayoutTextEdit *textEdit = NULL;
			
			if (lineEdit = qobject_cast<QLineEdit*>(item->widget())) {
				maxAscent = qMax(maxAscent,lineEdit->fontMetrics().ascent());
			}
			else if (textEdit = qobject_cast<VFlowLayoutTextEdit*>(item->widget())) {
				maxAscent = qMax(maxAscent,textEdit->calcFontAscent());
			}
		}
		else if (item->layout()) {
			VHBoxLayout *hLayout = qobject_cast<VHBoxLayout*>(item->layout());
			if (hLayout && hLayout->m_splitter->m_rows.count() > 0) {
				int wC = 0;
				hLayout->m_splitter->calcMaxAscent(hLayout->m_splitter->m_rows[0],maxAscent,wC);
			}
		}
		else {
			Q_ASSERT(false);
		}
	}
}

//
void VFlowLayoutSplitter::setGeometry(const QRect &rect)
{
/**********
	int left, top, right, bottom;
	m_flowLayout->getContentsMargins(&left, &top, &right, &bottom);
	QRect effectiveRect = rect.adjusted(+left, +top, -right, -bottom);

	int spaceX = item->widget()->style()->layoutSpacing(
		QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Horizontal
	);
**************/

	Qt::Alignment alignment = m_flowLayout->alignment();
	int y = rect.y();

	foreach (const VCols cols,m_rows) {
		int maxAscent = 0;
		int wCols = 0;

		calcMaxAscent(cols,maxAscent,wCols);

		int x = rect.x();
		int hCols = 0;
		int dX = rect.width() - wCols;
		
		if (alignment.testFlag(Qt::AlignHCenter)) {
			x += dX/2;
		}
		else if (alignment.testFlag(Qt::AlignRight)) {
			x += dX;
		}

		foreach (QLayoutItem *item,cols) {
			QPoint pt(x,y);
			QLineEdit *lineEdit = NULL;
			VFlowLayoutTextEdit *textEdit = NULL;

			if (lineEdit = qobject_cast<QLineEdit*>(item->widget())) {
				int dY = maxAscent - lineEdit->fontMetrics().ascent();
				pt.setY(pt.y() + dY);
			}
			else if (textEdit = qobject_cast<VFlowLayoutTextEdit*>(item->widget())) {
				int ascent = textEdit->calcFontAscent();
				
				if (ascent > 0) {
					int dY = maxAscent - ascent;
					pt.setY(pt.y() + dY);
				}
			}

			setGeometry(item,QRect(pt,sizeHint(item)));
			
			x += sizeHint(item).width();
			hCols = qMax(hCols,sizeHint(item).height());
		}

		y += hCols;
	}

//qDebug() << "setGeometry:" << rect;
//qDebug() << "setGeometry:" << y << " " << rect.bottom();
}

//
QSize VFlowLayoutSplitter::sizeHint(QLayoutItem *item) const
{
/*
	if (item->widget()) {
		return item->widget()->sizeHint();
	}
*/	
	return item->sizeHint();
}

//
QSize VFlowLayoutSplitter::minimumSize(QLayoutItem *item) const
{
/*
	if (item->widget()) {
		return item->widget()->minimumSize();
	}
*/	
	return item->minimumSize();
}

//
void VFlowLayoutSplitter::setGeometry(QLayoutItem *item,const QRect &rect)
{
/*
	if (item->widget()) {
		item->widget()->setGeometry(rect);
		return;
	}
*/	
	item->setGeometry(rect);
}

// VFlowLayout ////////////////////////////////////////////////////////////////

//
VFlowLayout::VFlowLayout(QWidget *parent)
	:QLayout(parent)
{
	m_params = new VFlowLayoutParams;
	m_splitter = VFlowLayoutSplitterPtr(new VFlowLayoutSplitter(this));

	//setHorizontalSpacing();
	//setVerticalSpacing();

	//setSizeConstraint(QLayout::SetMinAndMaxSize);
	setAlignment(Qt::AlignTop);// | Qt::AlignHCenter);
	setContentsMargins(0,0,0,0);
	setSpacing(0);
}

//
VFlowLayout::~VFlowLayout()
{
	QLayoutItem *item;
	while ((item = takeAt(0))) {
		delete item;
	}
	
	delete m_params;
}


/***************************
//
int VFlowLayout::horizontalSpacing() const
{
	if (m_hSpacing >= 0) {
		return m_hSpacing;
	}
	else {
		return smartSpacing(QStyle::PM_LayoutHorizontalSpacing);
	}
}

//
int VFlowLayout::verticalSpacing() const
{
	if (m_vSpacing >= 0) {
		return m_vSpacing;
	} 
	else {
		return smartSpacing(QStyle::PM_LayoutVerticalSpacing);
	}
}
****************************/

//
int VFlowLayout::pageWidth() const 
{ 
	if (!m_params->m_pageLayout) {
		VPageLayout *pageLayout = qobject_cast<VPageLayout*>(parent());
		m_params->m_pageLayout = pageLayout;
	}

	if (m_params->m_pageLayout) {
		return m_params->m_pageLayout->pageWidth();
	}

	return 0;
}

//
void VFlowLayout::addLayout(QLayout *layout)	
{
	addChildLayout(layout);
	addItem(layout);
	invalidate();
}

//
void VFlowLayout::addItem(QLayoutItem *item) 
{ 
	m_itemList.append(item);
	VFlowLayoutTextEdit *textEdit = qobject_cast<VFlowLayoutTextEdit*>(item->widget());
	if (textEdit) {
		textEdit->m_flowLayout = this;
		textEdit->setInFlowLayout(true);
		textEdit->slotContentsChanged();
	}

	//m_itemList.append(item);
	//invalidate();
}

//
QLayoutItem *VFlowLayout::itemAt(int index) const 
{ 
	if (index >= 0 && index < m_itemList.count()) {
		return m_itemList[index];
	}
	else {
		return NULL;
	}
}

//
QLayoutItem *VFlowLayout::takeAt(int index)
{
	if (index >= 0 && index < m_itemList.count()) {
		return m_itemList.takeAt(index);
	}
	else {
		return NULL;
	}
}

//
int VFlowLayout::heightForWidth(int width) const
{
	if (pageWidth() > 0) {
		width = pageWidth();
	}
	
	m_splitter->splitForWidth(width,m_itemList);
	int h = m_splitter->currentSize(m_itemList).height();

/*	
	if (m_invalidate != h) {
		m_invalidate = h;
		invalidate();
	}
*/	
	return h;
}

//
void VFlowLayout::setGeometry(const QRect &rect)
{
	QLayout::setGeometry(rect);
	m_splitter->setGeometry(rect);
	//QRect ar = alignmentRect(rect);

/*
	if (m_rect != rect) {
		m_rect = rect;
		QLayout *layout = static_cast<QLayout*>(this->parent());
		if (layout) {
			//invalidate();
			//layout->invalidate();
		}
	}
*/	

//layout = static_cast<QLayout*>(layout->parent());

/*
	//m_invalidate = 20;
	if (m_invalidate > 0) {
		m_invalidate--;
		invalidate();
	}
*/	
}

int VFlowLayout::smartSpacing(QStyle::PixelMetric pm) const
{
	QObject *parent = this->parent();
	
	if (!parent) {
		return -1;
	} 
	else if (parent->isWidgetType()) {
		QWidget *pw = static_cast<QWidget*>(parent);
		return pw->style()->pixelMetric(pm, 0, pw);
	} 
	else {
		return static_cast<QLayout*>(parent)->spacing();
	}
}






/****************************************
int VFlowLayout::doLayout(const QRect &rect, bool testOnly) const
{
    int left, top, right, bottom;
    getContentsMargins(&left, &top, &right, &bottom);
    QRect effectiveRect = rect.adjusted(+left, +top, -right, -bottom);
    int x = effectiveRect.x();
    int y = effectiveRect.y();
    int lineHeight = 0;
    
    foreach (QLayoutItem *item, m_itemList) {
        QWidget *wid = item->widget();
        
        int spaceX = horizontalSpacing();
        if (spaceX == -1) {
            spaceX = wid->style()->layoutSpacing(
                QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Horizontal
             );
        }
        
        int spaceY = verticalSpacing();
        if (spaceY == -1) {
            spaceY = wid->style()->layoutSpacing(
                QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Vertical);
        }

        int nextX = x + item->sizeHint().width() + spaceX;
        if (nextX - spaceX > effectiveRect.right() && lineHeight > 0) {
            x = effectiveRect.x();
            y = y + lineHeight + spaceY;
            nextX = x + item->sizeHint().width() + spaceX;
            lineHeight = 0;
        }

        if (!testOnly) {
            item->setGeometry(QRect(QPoint(x, y), item->sizeHint()));
        }

        x = nextX;
        lineHeight = qMax(lineHeight, item->sizeHint().height());
    }

//if (testOnly) {
	//lineHeight += 50;
//}

//lineHeight = m_splitter->size().height();

    return y + lineHeight - rect.y() + bottom;
}
*********************************************/